﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace APluginFramework.Common
{
    public delegate void  CallHandler(APlugin instance,string cmd,params object[] args);
    public abstract class APlugin
    {
        /// <summary>
        /// Sub Plugin
        /// </summary>
        private List<APlugin> children = new List<APlugin>();

        /// <summary>
        /// Call Root to do something
        /// </summary>
        public event CallHandler CallRootEvent;

        /// <summary>
        /// Call Other to do something, Root use this method to call some child to do something 
        /// </summary>
        public event CallHandler CallOtherEvent;

        private bool isRoot;
        /// <summary>
        /// this plugin is root or not
        /// </summary>
        public bool IsRoot
        {
            get { return isRoot; }
            set { isRoot = value; }
        }

        private APlugin parent;

        /// <summary>
        /// add child
        /// </summary>
        /// <param name="child"></param>
        public virtual void AddChild(APlugin child )
        {
            child.CallOtherEvent += APlugin_CallOther;
            child.CallRootEvent += APlugin_CallRoot;
            child.parent = parent;
            children.Add(child);
        }

        /// <summary>
        /// add children
        /// </summary>
        /// <param name="children"></param>
        public virtual void AddChildren(IEnumerable<APlugin> children)
        {
            foreach (var child in children)
            {
                AddChild(child);
            }
        }

        public APlugin()
        {
            
        }

        /// <summary>
        /// Call root to do something
        /// </summary>
        /// <param name="cmd">cmd</param>
        /// <param name="args">parameters</param>
        public  void CallRoot(string cmd, params object[] args)
        {
            if (CallRootEvent != null)
                CallRootEvent(this, cmd, args);
        }

        /// <summary>
        /// Call other to do something
        /// </summary>
        /// <param name="instance">plugin</param>
        /// <param name="cmd">cmd</param>
        /// <param name="args">parameters</param>
        public  void CallOther(APlugin instance,string cmd, params object[] args)
        {
            if (CallOtherEvent != null)
                CallOtherEvent(this, cmd, args);
        }

        public abstract void OnCallOther(APlugin instance,string cmd,params object[] args);
        public abstract void OnCallRoot(APlugin instance,string cmd,  params object[] args);

            
        private void APlugin_CallOther(APlugin instance, string cmd, params object[] args)
        {
            foreach (var child in children)
            {
                child.OnCallOther(instance, cmd, args);
                child.CallOther(instance, cmd, args);
            }
        }

        private void APlugin_CallRoot(APlugin instance, string cmd, params object[] args)
        {
            if (this.IsRoot)
            {
                this.OnCallRoot(instance, cmd, args);
            }
            else
            {
                APlugin root = FindRoot(this);
                root.OnCallRoot(instance, cmd, args);
            }
        }

        protected virtual APlugin FindRoot(APlugin plugin)
        {
            var parent = plugin.parent;
            while(!parent.IsRoot)
            {
                parent = parent.parent;
            }
            return parent;
        }

    }
}   
